package com.as.measurement.server;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Vector;

import com.as.measurement.model.ClientInterface;
import com.as.measurement.model.UserInterfaces;
import com.as.measurements.client.core.models.JperfStreamResult;
import com.as.measurements.client.core.models.Measurement;




public class Server extends Thread {

	private ArrayList<ClientInterface> interfaces = new ArrayList();

	/**
	 * @param args
	 */
	protected Socket socket;
	private InputStream input;
	private ServerSocket serverSocket;
	private Socket client;
	private String port;

	Server(Socket socket) {
		this.socket = socket;
	}

	public void closeServerSocket() throws IOException{
		System.out.println("********eyyyyy**************" + Thread.currentThread().getId());
		
		serverSocket.close();
		if (input != null && client != null && serverSocket != null) {
			
			System.out.println("**********pasamos por aqui************" + Thread.currentThread().getId());
		input.close();
		client.close();

		}
	}
	public Server(String port) {
		this.port = port;
	}
	
	public void init(){
		try {
			System.out.println("Starting on the port:" + port);
			 serverSocket = new ServerSocket(Integer.parseInt(port));
			// multithread server
			while (true) {
				client = serverSocket.accept();
				Server server = new Server(client);
				server.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// check if a port has been passed

			new Server("6969");


	}

	public void run() {
		
		System.out.println("********run**************" + Thread.currentThread().getId());

		try {
			socket.setSoTimeout(120000); // timeout=2min
			input = socket.getInputStream();
			// receive the object
			JperfStreamResult res = receiveResult();
			if (!res.equals(null)) {
				System.out.println("RECEIVED: ");
				for (int i = 0; i < interfaces.size(); i++) {
					// TODO

				}

				JperfStreamResult element = res;
				
				double bwResult = 0;
				double jitterResult = 0;
				double plResult = 0;

				//for (JperfStreamResult element : res) {
				
	

					/*
					 * Get all the measurement and calculate a mean value
					 */
					if (element != null) {
						
						if (element.getID() != -1){
						Vector<Measurement> bw = element.getBW();
						Vector<Measurement> jitter = element.getJitter();
						Vector<Measurement> pl = element.getPacketLoss();


						int indice = 0;
						for (Measurement m : bw) {

							if (m != null) {
								if (m.getValue() != 0) {
									bwResult += m.getValue();
									indice++;
								}
							}

						}
						// mean value
						if (indice != 0)
						bwResult = bwResult / indice;
						
						indice = 0;
						for (Measurement m : jitter) {

							if (m != null) {
								if (m.getValue() != 0) {
									jitterResult += m.getValue();
									indice++;
								}
							}

						}
						
						// mean value
						if (indice != 0)
						jitterResult = jitterResult / indice;
						
						// reset indice
						indice = 0;

						for (Measurement m : pl) {

							if (m != null) {
								if (m.getValue() != 0) {
									plResult += m.getValue();
									indice++;
								}
							}

						}
						// mean value
						if (indice != 0)
							plResult = plResult / indice;
						
						} else {
							
							bwResult = 0;
							jitterResult = 0;
							plResult =0;
						}
						// create the client interface and store it
						ClientInterface client;
						if (!UserInterfaces.getInstance().userInterfaces.containsKey(element.getInterfName())){
							 client = new ClientInterface(element.getInterfName());
							 UserInterfaces.getInstance().userInterfaces.put(element.getInterfName(), client);
						}else {
							client = UserInterfaces.getInstance().userInterfaces.get(element.getInterfName());

						}
						System.out.println( "adding values for interface: " + element.getInterfName());
						ArrayList test = client.get_bw();
						test.add(bwResult);
						client.get_jitter().add(jitterResult);
						client.get_pl().add(plResult);
						client.get_time().add(element.getStamp());
						System.out.println( "adding values for interface end" );

					}
				
				 printMeasurements();
					
				//}
				socket.close();
			}
		} catch (EOFException e) {
			System.out.println("Conection Reset by peer");
		} catch (IOException io) {
			io.printStackTrace();
		} catch (NullPointerException ex) {
			ex.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		finally {
			try {
				System.out.println("closing");
				input.close();
				socket.close();
			} catch (IOException ignored) {
				ignored.printStackTrace();
			}

		}

	}

	private JperfStreamResult receiveResult() throws Exception {
		try {
			PrintWriter out = new PrintWriter(socket.getOutputStream());
			ObjectInputStream ois = new ObjectInputStream(input);
			JperfStreamResult res = (JperfStreamResult) ois.readObject();
			// send the accept message to the client
			out.println("accept");
			out.flush();
			return res;
		} catch (java.io.StreamCorruptedException e) {
			System.err.println("Corrupted Stream Try Again");
			PrintWriter out = new PrintWriter(socket.getOutputStream());
			// send the message to the client
			out.println("Error Corrupted Stream");
			out.flush();
			// return receiveDescriptor();
			return null;
		}
	}
	
	
	private void printMeasurements(){
		
//		System.out.println("Size:  " + UserInterfaces.getInstance().userInterfaces.size());
		HashMap<String, ClientInterface> ht = UserInterfaces.getInstance().userInterfaces;

		
		Set<String> set = ht.keySet();

		for (String ee: set){
			
		
		ClientInterface client = UserInterfaces.userInterfaces.get(ee);
		
		ArrayList  total = client.get_bw();
		ArrayList  time = client.get_time();
		ArrayList  jitter = client.get_jitter();
		ArrayList  pltotal = client.get_pl();
		int count = 0;
		System.out.println( "********************************\n\n");
		for ( Object e: total ) {
			
			System.out.println( " Interface: " + ee + " BW: " + e  + " jitter: " + jitter.get(count) 
					
					+ " | Packet loss: " + pltotal.get(count) + " %" 
					+  " | Time: " + time.get(count)) ;
			count++;
		}
		System.out.println( "********************************\n\n");
		
		
		}
	}

}